#!/usr/bin/python
# -*-coding:UTF-8 -*-

# ========================
# @Time  : 2021/2/4
# @Author: Sunny
# ========================

import random
#通过装饰器实现单例模式，只要任意一个类使用该装饰器，那么就会变成一个单例模式的类
def docaretor(cls):
    """

    :param MyTest: 接收被装饰的函数和类
    :return:
    """
    one_dict={}
    def wrapper(*args,**kwargs):
        #判断字典中是否有这个类
        if not one_dict.get('cls'):
            #没有就先创建对象，并且保存到字典中去
            one_dict['cls'] = cls(*args, **kwargs)
            return one_dict['cls']
        else:
            #若有这个类，则直接返回这个类
            return one_dict['cls']
    return wrapper

@docaretor   #MyTest =  docaretor(MyTest)
class MyTest:
    a=1
    def dog(self):
        print('狗在跑')


M = MyTest()
N = MyTest()
print(id(M))
print(id(N))
M.dog()


#请实现一个类，前五次创建对象，每次都可以返回一个新的对象，第六次开始，每次创建，随机返回前5个对象中的一个
#用装饰器实现
def docaretor1(cls):
    """
    :param MyTest: 接收被装饰的函数和类
    :return:
    """
    one_list =[]
    i =1
    def wrapper(*args,**kwargs):
        while True:
            nonlocal i
            if i<6:
                obj = cls(*args, **kwargs)
                one_list.append(obj)
                i+=1
                return obj
            else:
                return random.choice(one_list)
    return wrapper

@docaretor1
class MyTest1:
    a=1
    def pig(self):
        print('猪在叫')


u = MyTest1()
v = MyTest1()
w = MyTest1()
x = MyTest1()
y = MyTest1()
z = MyTest1()
print(id(u))
print(id(v))
print(id(w))
print(id(x))
print(id(y))
print(id(z))
y.pig()

#用类实现
class Work2():
    __obj_list =[]

    @staticmethod
    def __new__(cls, *args, **kwargs):
        if len(cls.__obj_list)<5:
            obj = super().__new__(cls)
            cls.__obj_list.append(obj)
            return obj
        else:

            return random.choice(cls.__obj_list)
u = Work2()
v = Work2()
w = Work2()
x = Work2()
y = Work2()
z = Work2()
print(id(u))
print(id(v))
print(id(w))
print(id(x))
print(id(y))
print(id(z))



#通过类实现一个装饰器，既可以装饰函数，又可以装饰类，不管函数和类需不需要传参都可以装饰
class Decorator3:

    def __init__(self,obj):
        self.obj = obj

    def __call__(self, *args, **kwargs):
        return self.obj(*args,**kwargs)

@Decorator3   #MyTest3 = Decorator3(MyTest3)
class MyTest3():
    def __init__(self,name):
        self.name = name
    def dog(self):
        print(f'{self.name}狗在跑')

@Decorator3 #test = Decorator3(test)
def test(a):
    print(f'{a}执行函数功能')

test('A')
MyTest3('简').dog()





